package edu.neu.swc.commerce.config;


import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * <h1>通过Nacos下发动态路由配置，监听Nacos中的路由变更</h1>
 */
@Slf4j
@Component
@DependsOn({"gatewayConfig"})
public class DynamicRouteServiceImplByNacos {

    /** Nacos 配置服务 */
    private ConfigService configService;

    private final DynamicRouteServiceImpl dynamicRouteService;

    public DynamicRouteServiceImplByNacos(DynamicRouteServiceImpl dynamicRouteServiceImpl) {
        dynamicRouteService = dynamicRouteServiceImpl;
    }

    /**
     * <h2>链接到Nacos后需要做的事情</h2>
     * Bean在容器中构造完成后，会执行init方法
     */
    @PostConstruct
    public void init(){
        log.info("gateway route init...");

        try{
            //初始化Nacos配置客户端
            configService = initConfigService();
            if(null == configService){
                log.error("init config service fail");
                return;
            }

            //通过nacos Config并指定路由路径去获取路由配置
            //返回的是配置数据信息
            String configInfo = configService.getConfig(
                    GatewayConfig.NACOS_ROUTE_DATA_ID,
                    GatewayConfig.NACOS_ROUTE_GROUP,
                    GatewayConfig.DEFAULT_TIMEOUT
            );

            log.info("get current gateway config:[{}]", configInfo);

            List<RouteDefinition> definitionList =
                    JSON.parseArray(configInfo,RouteDefinition.class);

            if(!CollectionUtils.isEmpty(definitionList)){
                for (RouteDefinition definition : definitionList) {
                    log.info("init gateway config:[{}]", definition.toString());
                    dynamicRouteService.addRouteDefinition(definition);
                }
            }
        } catch (Exception ex){
            log.info("gateway route init has some errors:[{}]", ex.getMessage(),ex);

        }

        //设置监听器
        dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID,
                GatewayConfig.NACOS_ROUTE_GROUP);
    }

    /**
     * <h2>初始化NacosConfig</h2>
     */
    private ConfigService initConfigService(){
        try{
            Properties properties = new Properties();
            properties.setProperty("serverAddr",GatewayConfig.NACOS_SERVER_ADDR);
            properties.setProperty("namespace",GatewayConfig.NACOS_NAMESPACE);
            return configService = NacosFactory.createConfigService(properties);
        } catch (Exception ex){
            log.error("init gateway nacos config error:[{}]", ex.getMessage(),ex);
            return null;
        }
    }

    /**
     * <h2>监听Nacos下发的动态监听</h2>
     */
    private void dynamicRouteByNacosListener(String dataId, String group){
        try{
            //给客户端增加一个监听器
            configService.addListener(dataId, group, new Listener() {

                /**
                 * <h3>自己提供线程池操作</h3>
                 * @return 如果null
                 */
                @Override
                public Executor getExecutor() {
                    return null;
                }

                /**
                 * 监听器收到配置更新
                 * @param configInfo Nacos中最新的配置变化
                 */
                @Override
                public void receiveConfigInfo(String configInfo) {
                    List<RouteDefinition> definitionList =
                            JSON.parseArray(configInfo, RouteDefinition.class);
                    log.info("update route:[{}]",definitionList.toString());
                    //前面定义的路由更新操作
                    dynamicRouteService.updateList(definitionList);
                }
            });
        } catch (NacosException ex){
            log.error("dynamic update gateway config error:[{}]", ex.getMessage(),ex);
    }
    }
}
